home *** CD-ROM | disk | FTP | other *** search
- Subject: v24i018: GNU Diff, version 1.15, Part03/08
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: e98e62c7 1a384528 e8ba3cb5 deb69a40
-
- Submitted-by: Paul Eggert <eggert@twinsun.com>
- Posting-number: Volume 24, Issue 18
- Archive-name: gnudiff1.15/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 8)."
- # Contents: diff.c getopt.c util.c
- # Wrapped by eggert@ata on Mon Jan 7 11:25:29 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'diff.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'diff.c'\"
- else
- echo shar: Extracting \"'diff.c'\" \(17901 characters\)
- sed "s/^X//" >'diff.c' <<'END_OF_FILE'
- X/* GNU DIFF main routine.
- X Copyright (C) 1988, 1989 Free Software Foundation, Inc.
- X
- XThis file is part of GNU DIFF.
- X
- XGNU DIFF is free software; you can redistribute it and/or modify
- Xit under the terms of the GNU General Public License as published by
- Xthe Free Software Foundation; either version 1, or (at your option)
- Xany later version.
- X
- XGNU DIFF is distributed in the hope that it will be useful,
- Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
- XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- XGNU General Public License for more details.
- X
- XYou should have received a copy of the GNU General Public License
- Xalong with GNU DIFF; see the file COPYING. If not, write to
- Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- X
- X/* GNU DIFF was written by Mike Haertel, David Hayes,
- X Richard Stallman and Len Tower. */
- X
- X#define GDIFF_MAIN
- X#include "regex.h"
- X#include "diff.h"
- X#include "getopt.h"
- X
- X
- X/* Nonzero for -r: if comparing two directories,
- X compare their common subdirectories recursively. */
- X
- Xint recursive;
- X
- X/* For debugging: don't do discard_confusing_lines. */
- X
- Xint no_discards;
- X
- X/* Return a string containing the command options with which diff was invoked.
- X Spaces appear between what were separate ARGV-elements.
- X There is a space at the beginning but none at the end.
- X If there were no options, the result is an empty string.
- X
- X Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT,
- X the length of that vector. */
- X
- Xstatic char *
- Xoption_list (optionvec, count)
- X char **optionvec; /* Was `vector', but that collides on Alliant. */
- X int count;
- X{
- X int i;
- X int length = 0;
- X char *result;
- X
- X for (i = 0; i < count; i++)
- X length += strlen (optionvec[i]) + 1;
- X
- X result = (char *) xmalloc (length + 1);
- X result[0] = 0;
- X
- X for (i = 0; i < count; i++)
- X {
- X strcat (result, " ");
- X strcat (result, optionvec[i]);
- X }
- X
- X return result;
- X}
- X
- X/* The numbers 129 and 130 that appear in the fourth element
- X for the context and unidiff entries are used as a way of
- X telling the big switch in `main' how to process those options. */
- X
- Xstatic struct option longopts[] =
- X{
- X {"ignore-blank-lines", 0, 0, 'B'},
- X {"context", 2, 0, 129},
- X {"ifdef", 1, 0, 'D'},
- X {"show-function-line", 1, 0, 'F'},
- X {"speed-large-files", 0, 0, 'H'},
- X {"ignore-matching-lines", 1, 0, 'I'},
- X {"file-label", 1, 0, 'L'},
- X {"entire-new-files", 0, 0, 'N'},
- X {"new-files", 0, 0, 'N'},
- X {"starting-file", 1, 0, 'S'},
- X {"initial-tab", 0, 0, 'T'},
- X {"text", 0, 0, 'a'},
- X {"all-text", 0, 0, 'a'},
- X {"ascii", 0, 0, 'a'},
- X {"ignore-space-change", 0, 0, 'b'},
- X {"minimal", 0, 0, 'd'},
- X {"ed", 0, 0, 'e'},
- X {"reversed-ed", 0, 0, 'f'},
- X {"ignore-case", 0, 0, 'i'},
- X {"print", 0, 0, 'l'},
- X {"rcs", 0, 0, 'n'},
- X {"show-c-function", 0, 0, 'p'},
- X {"binary", 0, 0, 'q'},
- X {"brief", 0, 0, 'q'},
- X {"recursive", 0, 0, 'r'},
- X {"report-identical-files", 0, 0, 's'},
- X {"expand-tabs", 0, 0, 't'},
- X {"ignore-all-space", 0, 0, 'w'},
- X {"unified", 2, 0, 130},
- X {"version", 0, 0, 'v'},
- X {0, 0, 0, 0}
- X};
- X
- Xmain (argc, argv)
- X int argc;
- X char *argv[];
- X{
- X int val;
- X int c;
- X int prev = -1;
- X int longind;
- X extern char *version_string;
- X
- X program = argv[0];
- X
- X /* Do our initializations. */
- X output_style = OUTPUT_NORMAL;
- X always_text_flag = FALSE;
- X ignore_space_change_flag = FALSE;
- X ignore_all_space_flag = FALSE;
- X length_varies = FALSE;
- X ignore_case_flag = FALSE;
- X ignore_blank_lines_flag = FALSE;
- X ignore_regexp = 0;
- X function_regexp = 0;
- X print_file_same_flag = FALSE;
- X entire_new_file_flag = FALSE;
- X no_details_flag = FALSE;
- X context = -1;
- X line_end_char = '\n';
- X tab_align_flag = FALSE;
- X tab_expand_flag = FALSE;
- X recursive = FALSE;
- X paginate_flag = FALSE;
- X ifdef_string = NULL;
- X heuristic = FALSE;
- X dir_start_file = NULL;
- X msg_chain = NULL;
- X msg_chain_end = NULL;
- X no_discards = 0;
- X
- X /* Decode the options. */
- X
- X while ((c = getopt_long (argc, argv,
- X "0123456789abBcC:dD:efF:hHiI:lL:nNpqrsS:tTuvw",
- X longopts, &longind)) != EOF)
- X {
- X if (c == 0) /* Long option. */
- X c = longopts[longind].val;
- X switch (c)
- X {
- X /* All digits combine in decimal to specify the context-size. */
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X case '0':
- X if (context == -1)
- X context = 0;
- X /* If a context length has already been specified,
- X more digits allowed only if they follow right after the others.
- X Reject two separate runs of digits, or digits after -C. */
- X else if (prev < '0' || prev > '9')
- X fatal ("context length specified twice");
- X
- X context = context * 10 + c - '0';
- X break;
- X
- X case 'a':
- X /* Treat all files as text files; never treat as binary. */
- X always_text_flag = 1;
- X break;
- X
- X case 'b':
- X /* Ignore changes in amount of whitespace. */
- X ignore_space_change_flag = 1;
- X length_varies = 1;
- X break;
- X
- X case 'B':
- X /* Ignore changes affecting only blank lines. */
- X ignore_blank_lines_flag = 1;
- X break;
- X
- X case 'C':
- X case 129: /* +context[=lines] */
- X case 130: /* +unified[=lines] */
- X if (optarg)
- X {
- X if (context >= 0)
- X fatal ("context length specified twice");
- X {
- X char *p;
- X for (p = optarg; *p; p++)
- X if (*p < '0' || *p > '9')
- X fatal ("invalid context length argument");
- X }
- X context = atoi (optarg);
- X }
- X
- X /* Falls through. */
- X case 'c':
- X /* Make context-style output. */
- X specify_style (c == 130 ? OUTPUT_UNIFIED : OUTPUT_CONTEXT);
- X break;
- X
- X case 'd':
- X /* Don't discard lines. This makes things slower (sometimes much
- X slower) but will find a guaranteed minimal set of changes. */
- X no_discards = 1;
- X break;
- X
- X case 'D':
- X /* Make merged #ifdef output. */
- X specify_style (OUTPUT_IFDEF);
- X ifdef_string = optarg;
- X break;
- X
- X case 'e':
- X /* Make output that is a valid `ed' script. */
- X specify_style (OUTPUT_ED);
- X break;
- X
- X case 'f':
- X /* Make output that looks vaguely like an `ed' script
- X but has changes in the order they appear in the file. */
- X specify_style (OUTPUT_FORWARD_ED);
- X break;
- X
- X case 'F':
- X /* Show, for each set of changes, the previous line that
- X matches the specified regexp. Currently affects only
- X context-style output. */
- X function_regexp = optarg;
- X break;
- X
- X case 'h':
- X /* Split the files into chunks of around 1500 lines
- X for faster processing. Usually does not change the result.
- X
- X This currently has no effect. */
- X break;
- X
- X case 'H':
- X /* Turn on heuristics that speed processing of large files
- X with a small density of changes. */
- X heuristic = 1;
- X break;
- X
- X case 'i':
- X /* Ignore changes in case. */
- X ignore_case_flag = 1;
- X break;
- X
- X case 'I':
- X /* Ignore changes affecting only lines that match the
- X specified regexp. */
- X ignore_regexp = optarg;
- X break;
- X
- X case 'l':
- X /* Pass the output through `pr' to paginate it. */
- X paginate_flag = 1;
- X break;
- X
- X case 'L':
- X /* Specify file labels for `-c' output headers. */
- X if (!file_label[0])
- X file_label[0] = optarg;
- X else if (!file_label[1])
- X file_label[1] = optarg;
- X else
- X fatal ("too many file label options");
- X break;
- X
- X case 'n':
- X /* Output RCS-style diffs, like `-f' except that each command
- X specifies the number of lines affected. */
- X specify_style (OUTPUT_RCS);
- X break;
- X
- X case 'N':
- X /* When comparing directories, if a file appears only in one
- X directory, treat it as present but empty in the other. */
- X entire_new_file_flag = 1;
- X break;
- X
- X case 'p':
- X /* Make context-style output and show name of last C function. */
- X specify_style (OUTPUT_CONTEXT);
- X function_regexp = "^[_a-zA-Z]";
- X break;
- X
- X case 'q':
- X no_details_flag = 1;
- X break;
- X
- X case 'r':
- X /* When comparing directories,
- X recursively compare any subdirectories found. */
- X recursive = 1;
- X break;
- X
- X case 's':
- X /* Print a message if the files are the same. */
- X print_file_same_flag = 1;
- X break;
- X
- X case 'S':
- X /* When comparing directories, start with the specified
- X file name. This is used for resuming an aborted comparison. */
- X dir_start_file = optarg;
- X break;
- X
- X case 't':
- X /* Expand tabs to spaces in the output so that it preserves
- X the alignment of the input files. */
- X tab_expand_flag = 1;
- X break;
- X
- X case 'T':
- X /* Use a tab in the output, rather than a space, before the
- X text of an input line, so as to keep the proper alignment
- X in the input line without changing the characters in it. */
- X tab_align_flag = 1;
- X break;
- X
- X case 'v':
- X printf ("GNU diff version %s\n", version_string);
- X break;
- X
- X case 'u':
- X /* Output the context diff in unidiff format. */
- X specify_style (OUTPUT_UNIFIED);
- X break;
- X
- X case 'w':
- X /* Ignore horizontal whitespace when comparing lines. */
- X ignore_all_space_flag = 1;
- X length_varies = 1;
- X break;
- X
- X default:
- X usage ();
- X }
- X prev = c;
- X }
- X
- X if (optind != argc - 2)
- X usage ();
- X
- X if (ignore_regexp)
- X {
- X char *val;
- X bzero (&ignore_regexp_compiled, sizeof ignore_regexp_compiled);
- X val = re_compile_pattern (ignore_regexp, strlen (ignore_regexp),
- X &ignore_regexp_compiled);
- X if (val != 0)
- X error ("%s: %s", ignore_regexp, val);
- X ignore_regexp_compiled.fastmap = (char *) xmalloc (256);
- X }
- X
- X if (function_regexp)
- X {
- X char *val;
- X bzero (&function_regexp_compiled, sizeof function_regexp_compiled);
- X val = re_compile_pattern (function_regexp, strlen (function_regexp),
- X &function_regexp_compiled);
- X if (val != 0)
- X error ("%s: %s", function_regexp, val);
- X function_regexp_compiled.fastmap = (char *) xmalloc (256);
- X }
- X
- X if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED)
- X context = 0;
- X else if (context == -1)
- X /* Default amount of context for -c. */
- X context = 3;
- X
- X switch_string = option_list (argv + 1, optind - 1);
- X
- X val = compare_files (0, argv[optind], 0, argv[optind + 1], 0);
- X
- X /* Print any messages that were saved up for last. */
- X print_message_queue ();
- X
- X if (ferror (stdout) || fclose (stdout) != 0)
- X fatal ("write error");
- X exit (val);
- X}
- X
- Xusage ()
- X{
- X fprintf (stderr, "\
- XUsage: diff [-#] [-abBcdefhHilnNprstTuvw] [-C lines] [-F regexp] [-I regexp]\n\
- X [-L label [-L label]] [-S file] [-D symbol] [+ignore-blank-lines]\n\
- X [+context[=lines]] [+unified[=lines]] [+ifdef=symbol]\n\
- X [+show-function-line=regexp]\n");
- X fprintf (stderr, "\
- X [+speed-large-files] [+ignore-matching-lines=regexp] [+new-file]\n\
- X [+initial-tab] [+starting-file=file] [+text] [+all-text] [+ascii]\n\
- X [+minimal] [+ignore-space-change] [+ed] [+reversed-ed] [+ignore-case]\n");
- X fprintf (stderr, "\
- X [+print] [+rcs] [+show-c-function] [+binary] [+brief] [+recursive]\n\
- X [+report-identical-files] [+expand-tabs] [+ignore-all-space]\n\
- X [+file-label=label [+file-label=label]] [+version] path1 path2\n");
- X exit (2);
- X}
- X
- Xspecify_style (style)
- X enum output_style style;
- X{
- X if (output_style != OUTPUT_NORMAL
- X && output_style != style)
- X error ("conflicting specifications of output style");
- X output_style = style;
- X}
- X
- X/* Compare two files (or dirs) with specified names
- X DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion.
- X (if DIR0 is 0, then the name is just NAME0, etc.)
- X This is self-contained; it opens the files and closes them.
- X
- X Value is 0 if files are identical, 1 if different,
- X 2 if there is a problem opening them. */
- X
- Xint
- Xcompare_files (dir0, name0, dir1, name1, depth)
- X char *dir0, *dir1;
- X char *name0, *name1;
- X int depth;
- X{
- X static char Standard_Input[] = "Standard Input";
- X struct file_data inf[2];
- X register int i;
- X int val;
- X int errorcount = 0;
- X int stat_result[2];
- X
- X /* If this is directory comparison, perhaps we have a file
- X that exists only in one of the directories.
- X If so, just print a message to that effect. */
- X
- X if (! entire_new_file_flag && (name0 == 0 || name1 == 0))
- X {
- X char *name = name0 == 0 ? name1 : name0;
- X char *dir = name0 == 0 ? dir1 : dir0;
- X message ("Only in %s: %s\n", dir, name);
- X /* Return 1 so that diff_dirs will return 1 ("some files differ"). */
- X return 1;
- X }
- X
- X /* Mark any nonexistent file with -1 in the desc field. */
- X /* Mark unopened files (i.e. directories) with -2. */
- X
- X inf[0].desc = name0 == 0 ? -1 : -2;
- X inf[1].desc = name1 == 0 ? -1 : -2;
- X
- X /* Now record the full name of each file, including nonexistent ones. */
- X
- X if (name0 == 0)
- X name0 = name1;
- X if (name1 == 0)
- X name1 = name0;
- X
- X inf[0].name = dir0 == 0 ? name0 : concat (dir0, "/", name0);
- X inf[1].name = dir1 == 0 ? name1 : concat (dir1, "/", name1);
- X
- X /* Stat the files. Record whether they are directories.
- X Record in stat_result whether stat fails. */
- X
- X for (i = 0; i <= 1; i++)
- X {
- X bzero (&inf[i].stat, sizeof(struct stat));
- X inf[i].dir_p = 0;
- X stat_result[i] = 0;
- X
- X if (inf[i].desc != -1)
- X {
- X char *filename = inf[i].name;
- X
- X stat_result[i] =
- X strcmp (filename, "-")
- X ? stat (filename, &inf[i].stat)
- X : fstat (0, &inf[i].stat);
- X
- X if (stat_result[i] < 0)
- X {
- X perror_with_name (filename);
- X errorcount = 1;
- X }
- X else
- X inf[i].dir_p =
- X S_IFDIR == (inf[i].stat.st_mode & S_IFMT)
- X && strcmp (filename, "-");
- X }
- X }
- X
- X /* See if the two named files are actually the same physical file.
- X If so, we know they are identical without actually reading them. */
- X
- X if (output_style != OUTPUT_IFDEF
- X && inf[0].stat.st_ino == inf[1].stat.st_ino
- X && inf[0].stat.st_dev == inf[1].stat.st_dev
- X && stat_result[0] == 0
- X && stat_result[1] == 0)
- X {
- X val = 0;
- X goto done;
- X }
- X
- X if (name0 == 0)
- X inf[0].dir_p = inf[1].dir_p;
- X if (name1 == 0)
- X inf[1].dir_p = inf[0].dir_p;
- X
- X /* Open the files and record their descriptors. */
- X
- X for (i = 0; i <= 1; i++)
- X {
- X if (inf[i].desc == -1)
- X ;
- X else if (!strcmp (inf[i].name, "-"))
- X {
- X inf[i].desc = 0;
- X inf[i].name = Standard_Input;
- X }
- X /* Don't bother opening if stat already failed. */
- X else if (stat_result[i] == 0 && ! inf[i].dir_p)
- X {
- X char *filename = inf[i].name;
- X
- X inf[i].desc = open (filename, O_RDONLY, 0);
- X if (0 > inf[i].desc)
- X {
- X perror_with_name (filename);
- X errorcount = 1;
- X }
- X }
- X }
- X
- X if (errorcount)
- X {
- X
- X /* If either file should exist but fails to be opened, return 2. */
- X
- X val = 2;
- X
- X }
- X else if (inf[0].dir_p && inf[1].dir_p)
- X {
- X if (output_style == OUTPUT_IFDEF)
- X fatal ("-D option not supported with directories");
- X
- X /* If both are directories, compare the files in them. */
- X
- X if (depth > 0 && !recursive)
- X {
- X /* But don't compare dir contents one level down
- X unless -r was specified. */
- X message ("Common subdirectories: %s and %s\n",
- X inf[0].name, inf[1].name);
- X val = 0;
- X }
- X else
- X {
- X val = diff_dirs (inf[0].name, inf[1].name,
- X compare_files, depth, 0, 0);
- X }
- X
- X }
- X else if (depth == 0 && (inf[0].dir_p || inf[1].dir_p))
- X {
- X
- X /* If only one is a directory, and it was specified in the command line,
- X use the file in that dir whose basename matches the other file. */
- X
- X int dir_arg = (inf[0].dir_p ? 0 : 1);
- X int fnm_arg = (inf[0].dir_p ? 1 : 0);
- X char *p = rindex (inf[fnm_arg].name, '/');
- X char *filename = concat (inf[dir_arg].name, "/",
- X (p ? p+1 : inf[fnm_arg].name));
- X
- X if (inf[fnm_arg].name == Standard_Input)
- X fatal ("can't compare - to a directory");
- X
- X inf[dir_arg].desc = open (filename, O_RDONLY, 0);
- X
- X if (0 > inf[dir_arg].desc)
- X {
- X perror_with_name (filename);
- X val = 2;
- X }
- X else
- X {
- X /* JF: patch from the net to check and make sure we can really free
- X this. If it's from argv[], freeing it is a *really* bad idea */
- X if (0 != (dir_arg ? dir1 : dir0))
- X free (inf[dir_arg].name);
- X inf[dir_arg].name = filename;
- X if (fstat (inf[dir_arg].desc, &inf[dir_arg].stat) < 0)
- X pfatal_with_name (inf[dir_arg].name);
- X
- X inf[dir_arg].dir_p
- X = (S_IFDIR == (inf[dir_arg].stat.st_mode & S_IFMT));
- X if (inf[dir_arg].dir_p)
- X {
- X error ("%s is a directory but %s is not",
- X inf[dir_arg].name, inf[fnm_arg].name);
- X val = 1;
- X }
- X else
- X val = diff_2_files (inf, depth);
- X }
- X
- X }
- X else if (depth > 0 && (inf[0].dir_p || inf[1].dir_p))
- X {
- X /* Perhaps we have a subdirectory that exists only in one directory.
- X If so, just print a message to that effect. */
- X
- X if (inf[0].desc == -1 || inf[1].desc == -1)
- X {
- X if (entire_new_file_flag && recursive)
- X val = diff_dirs (inf[0].name, inf[1].name, compare_files, depth,
- X inf[0].desc == -1, inf[1].desc == -1);
- X else
- X {
- X char *dir = (inf[0].desc == -1) ? dir1 : dir0;
- X message ("Only in %s: %s\n", dir, name0);
- X val = 1;
- X }
- X }
- X else
- X {
- X /* We have a subdirectory in one directory
- X and a file in the other. */
- X
- X if (inf[0].dir_p)
- X message ("%s is a directory but %s is not\n",
- X inf[0].name, inf[1].name);
- X else
- X message ("%s is a directory but %s is not\n",
- X inf[1].name, inf[0].name);
- X /* This is a difference. */
- X val = 1;
- X }
- X }
- X else
- X {
- X
- X /* Both exist and both are ordinary files. */
- X
- X val = diff_2_files (inf, depth);
- X
- X }
- X
- X /* Now the comparison has been done, if no error prevented it,
- X and VAL is the value this function will return. */
- X
- X if (inf[0].desc >= 0)
- X close (inf[0].desc);
- X if (inf[1].desc >= 0)
- X close (inf[1].desc);
- X
- X done:
- X if (val == 0 && !inf[0].dir_p)
- X {
- X if (print_file_same_flag)
- X message ("Files %s and %s are identical\n",
- X inf[0].name, inf[1].name);
- X }
- X else
- X fflush (stdout);
- X
- X if (dir0 != 0)
- X free (inf[0].name);
- X if (dir1 != 0)
- X free (inf[1].name);
- X
- X return val;
- X}
- END_OF_FILE
- if test 17901 -ne `wc -c <'diff.c'`; then
- echo shar: \"'diff.c'\" unpacked with wrong size!
- fi
- # end of 'diff.c'
- fi
- if test -f 'getopt.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'getopt.c'\"
- else
- echo shar: Extracting \"'getopt.c'\" \(16740 characters\)
- sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
- X/* Getopt for GNU.
- X Copyright (C) 1987, 1989, 1990 Free Software Foundation, Inc.
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 1, or (at your option)
- X any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- X
- X#ifdef __STDC__
- X#define CONST const
- X#else
- X#define CONST
- X#endif
- X
- X/* This version of `getopt' appears to the caller like standard Unix `getopt'
- X but it behaves differently for the user, since it allows the user
- X to intersperse the options with the other arguments.
- X
- X As `getopt' works, it permutes the elements of `argv' so that,
- X when it is done, all the options precede everything else. Thus
- X all application programs are extended to handle flexible argument order.
- X
- X Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
- X Then the behavior is completely standard.
- X
- X GNU application programs can use a third alternative mode in which
- X they can distinguish the relative order of options and other arguments. */
- X
- X#include <stdio.h>
- X
- X/* If compiled with GNU C, use the built-in alloca */
- X#ifdef __GNUC__
- X#define alloca __builtin_alloca
- X#else /* not __GNUC__ */
- X#ifdef sparc
- X#include <alloca.h>
- X#else
- Xchar *alloca ();
- X#endif
- X#endif /* not __GNUC__ */
- X
- X#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
- X#include <stdlib.h>
- X#include <string.h>
- X#define bcopy(s, d, n) memcpy ((d), (s), (n))
- X#define index strchr
- X#else
- X
- X#ifdef USG
- X#include <string.h>
- X#define bcopy(s, d, n) memcpy ((d), (s), (n))
- X#define index strchr
- X#else
- X#ifdef VMS
- X#include <string.h>
- X#else
- X#include <strings.h>
- X#endif
- Xvoid bcopy ();
- X#endif
- X
- Xchar *getenv ();
- Xchar *malloc ();
- X#endif
- X
- X/* For communication from `getopt' to the caller.
- X When `getopt' finds an option that takes an argument,
- X the argument value is returned here.
- X Also, when `ordering' is RETURN_IN_ORDER,
- X each non-option ARGV-element is returned here. */
- X
- Xchar *optarg = 0;
- X
- X/* Index in ARGV of the next element to be scanned.
- X This is used for communication to and from the caller
- X and for communication between successive calls to `getopt'.
- X
- X On entry to `getopt', zero means this is the first call; initialize.
- X
- X When `getopt' returns EOF, this is the index of the first of the
- X non-option elements that the caller should itself scan.
- X
- X Otherwise, `optind' communicates from one call to the next
- X how much of ARGV has been scanned so far. */
- X
- Xint optind = 0;
- X
- X/* The next char to be scanned in the option-element
- X in which the last option character we returned was found.
- X This allows us to pick up the scan where we left off.
- X
- X If this is zero, or a null string, it means resume the scan
- X by advancing to the next ARGV-element. */
- X
- Xstatic char *nextchar;
- X
- X/* Callers store zero here to inhibit the error message
- X for unrecognized options. */
- X
- Xint opterr = 1;
- X
- X/* Describe how to deal with options that follow non-option ARGV-elements.
- X
- X If the caller did not specify anything,
- X the default is REQUIRE_ORDER if the environment variable
- X _POSIX_OPTION_ORDER is defined, PERMUTE otherwise.
- X
- X REQUIRE_ORDER means don't recognize them as options;
- X stop option processing when the first non-option is seen.
- X This is what Unix does.
- X This mode of operation is selected by either setting the environment
- X variable _POSIX_OPTION_ORDER, or using `+' as the first character
- X of the list of option characters.
- X
- X PERMUTE is the default. We permute the contents of ARGV as we scan,
- X so that eventually all the non-options are at the end. This allows options
- X to be given in any order, even with programs that were not written to
- X expect this.
- X
- X RETURN_IN_ORDER is an option available to programs that were written
- X to expect options and other ARGV-elements in any order and that care about
- X the ordering of the two. We describe each non-option ARGV-element
- X as if it were the argument of an option with character code 1.
- X Using `-' as the first character of the list of option characters
- X selects this mode of operation.
- X
- X The special argument `--' forces an end of option-scanning regardless
- X of the value of `ordering'. In the case of RETURN_IN_ORDER, only
- X `--' can cause `getopt' to return EOF with `optind' != ARGC. */
- X
- Xstatic enum
- X{
- X REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
- X} ordering;
- X
- X/* Describe the long-named options requested by the application.
- X _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
- X element containing a name which is zero.
- X The field `has_arg' is 1 if the option takes an argument,
- X 2 if it takes an optional argument. */
- X
- Xstruct option
- X{
- X char *name;
- X int has_arg;
- X int *flag;
- X int val;
- X};
- X
- XCONST struct option *_getopt_long_options;
- X
- Xint _getopt_long_only = 0;
- X
- X/* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found.
- X Only valid when a long-named option was found. */
- X
- Xint option_index;
- X
- X/* Handle permutation of arguments. */
- X
- X/* Describe the part of ARGV that contains non-options that have
- X been skipped. `first_nonopt' is the index in ARGV of the first of them;
- X `last_nonopt' is the index after the last of them. */
- X
- Xstatic int first_nonopt;
- Xstatic int last_nonopt;
- X
- X/* Exchange two adjacent subsequences of ARGV.
- X One subsequence is elements [first_nonopt,last_nonopt)
- X which contains all the non-options that have been skipped so far.
- X The other is elements [last_nonopt,optind), which contains all
- X the options processed since those non-options were skipped.
- X
- X `first_nonopt' and `last_nonopt' are relocated so that they describe
- X the new indices of the non-options in ARGV after they are moved. */
- X
- Xstatic void
- Xexchange (argv)
- X char **argv;
- X{
- X int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
- X char **temp = (char **) alloca (nonopts_size);
- X
- X /* Interchange the two blocks of data in ARGV. */
- X
- X bcopy (&argv[first_nonopt], temp, nonopts_size);
- X bcopy (&argv[last_nonopt], &argv[first_nonopt],
- X (optind - last_nonopt) * sizeof (char *));
- X bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
- X
- X /* Update records for the slots the non-options now occupy. */
- X
- X first_nonopt += (optind - last_nonopt);
- X last_nonopt = optind;
- X}
- X
- X/* Scan elements of ARGV (whose length is ARGC) for option characters
- X given in OPTSTRING.
- X
- X If an element of ARGV starts with '-', and is not exactly "-" or "--",
- X then it is an option element. The characters of this element
- X (aside from the initial '-') are option characters. If `getopt'
- X is called repeatedly, it returns successively each of the option characters
- X from each of the option elements.
- X
- X If `getopt' finds another option character, it returns that character,
- X updating `optind' and `nextchar' so that the next call to `getopt' can
- X resume the scan with the following option character or ARGV-element.
- X
- X If there are no more option characters, `getopt' returns `EOF'.
- X Then `optind' is the index in ARGV of the first ARGV-element
- X that is not an option. (The ARGV-elements have been permuted
- X so that those that are not options now come last.)
- X
- X OPTSTRING is a string containing the legitimate option characters.
- X If an option character is seen that is not listed in OPTSTRING,
- X return '?' after printing an error message. If you set `opterr' to
- X zero, the error message is suppressed but we still return '?'.
- X
- X If a char in OPTSTRING is followed by a colon, that means it wants an arg,
- X so the following text in the same ARGV-element, or the text of the following
- X ARGV-element, is returned in `optarg'. Two colons mean an option that
- X wants an optional arg; if there is text in the current ARGV-element,
- X it is returned in `optarg', otherwise `optarg' is set to zero.
- X
- X If OPTSTRING starts with `-' or `+', it requests different methods of
- X handling the non-option ARGV-elements.
- X See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
- X
- X Long-named options begin with `+' instead of `-'.
- X Their names may be abbreviated as long as the abbreviation is unique
- X or is an exact match for some defined option. If they have an
- X argument, it follows the option name in the same ARGV-element, separated
- X from the option name by a `=', or else the in next ARGV-element.
- X When `getopt' finds a long-named option, it returns 0 if that option's
- X `flag' field is nonzero, the value of the option's `val' field
- X otherwise. */
- X
- Xint
- Xgetopt (argc, argv, optstring)
- X int argc;
- X char **argv;
- X CONST char *optstring;
- X{
- X optarg = 0;
- X
- X /* Initialize the internal data when the first call is made.
- X Start processing options with ARGV-element 1 (since ARGV-element 0
- X is the program name); the sequence of previously skipped
- X non-option ARGV-elements is empty. */
- X
- X if (optind == 0)
- X {
- X first_nonopt = last_nonopt = optind = 1;
- X
- X nextchar = 0;
- X
- X /* Determine how to handle the ordering of options and nonoptions. */
- X
- X if (optstring[0] == '-')
- X {
- X ordering = RETURN_IN_ORDER;
- X ++optstring;
- X }
- X else if (optstring[0] == '+')
- X {
- X ordering = REQUIRE_ORDER;
- X ++optstring;
- X }
- X else if (getenv ("_POSIX_OPTION_ORDER") != 0)
- X ordering = REQUIRE_ORDER;
- X else
- X ordering = PERMUTE;
- X }
- X
- X if (nextchar == 0 || *nextchar == 0)
- X {
- X if (ordering == PERMUTE)
- X {
- X /* If we have just processed some options following some non-options,
- X exchange them so that the options come first. */
- X
- X if (first_nonopt != last_nonopt && last_nonopt != optind)
- X exchange (argv);
- X else if (last_nonopt != optind)
- X first_nonopt = optind;
- X
- X /* Now skip any additional non-options
- X and extend the range of non-options previously skipped. */
- X
- X while (optind < argc
- X && (argv[optind][0] != '-'
- X || argv[optind][1] == 0)
- X && (_getopt_long_options == 0
- X || argv[optind][0] != '+'
- X || argv[optind][1] == 0))
- X optind++;
- X last_nonopt = optind;
- X }
- X
- X /* Special ARGV-element `--' means premature end of options.
- X Skip it like a null option,
- X then exchange with previous non-options as if it were an option,
- X then skip everything else like a non-option. */
- X
- X if (optind != argc && !strcmp (argv[optind], "--"))
- X {
- X optind++;
- X
- X if (first_nonopt != last_nonopt && last_nonopt != optind)
- X exchange (argv);
- X else if (first_nonopt == last_nonopt)
- X first_nonopt = optind;
- X last_nonopt = argc;
- X
- X optind = argc;
- X }
- X
- X /* If we have done all the ARGV-elements, stop the scan
- X and back over any non-options that we skipped and permuted. */
- X
- X if (optind == argc)
- X {
- X /* Set the next-arg-index to point at the non-options
- X that we previously skipped, so the caller will digest them. */
- X if (first_nonopt != last_nonopt)
- X optind = first_nonopt;
- X return EOF;
- X }
- X
- X /* If we have come to a non-option and did not permute it,
- X either stop the scan or describe it to the caller and pass it by. */
- X
- X if ((argv[optind][0] != '-' || argv[optind][1] == 0)
- X && (_getopt_long_options == 0
- X || argv[optind][0] != '+' || argv[optind][1] == 0))
- X {
- X if (ordering == REQUIRE_ORDER)
- X return EOF;
- X optarg = argv[optind++];
- X return 1;
- X }
- X
- X /* We have found another option-ARGV-element.
- X Start decoding its characters. */
- X
- X nextchar = argv[optind] + 1;
- X }
- X
- X if (_getopt_long_options != 0
- X && (argv[optind][0] == '+'
- X || (_getopt_long_only && argv[optind][0] == '-'))
- X )
- X {
- X CONST struct option *p;
- X char *s = nextchar;
- X int exact = 0;
- X int ambig = 0;
- X CONST struct option *pfound = 0;
- X int indfound;
- X
- X while (*s && *s != '=')
- X s++;
- X
- X /* Test all options for either exact match or abbreviated matches. */
- X for (p = _getopt_long_options, option_index = 0; p->name;
- X p++, option_index++)
- X if (!strncmp (p->name, nextchar, s - nextchar))
- X {
- X if (s - nextchar == strlen (p->name))
- X {
- X /* Exact match found. */
- X pfound = p;
- X indfound = option_index;
- X exact = 1;
- X break;
- X }
- X else if (pfound == 0)
- X {
- X /* First nonexact match found. */
- X pfound = p;
- X indfound = option_index;
- X }
- X else
- X /* Second nonexact match found. */
- X ambig = 1;
- X }
- X
- X if (ambig && !exact)
- X {
- X fprintf (stderr, "%s: option `%s' is ambiguous\n",
- X argv[0], argv[optind]);
- X nextchar += strlen (nextchar);
- X optind++;
- X return '?';
- X }
- X
- X if (pfound != 0)
- X {
- X option_index = indfound;
- X optind++;
- X if (*s)
- X {
- X if (pfound->has_arg > 0)
- X optarg = s + 1;
- X else
- X {
- X fprintf (stderr,
- X "%s: option `%c%s' doesn't allow an argument\n",
- X argv[0], argv[optind - 1][0], pfound->name);
- X nextchar += strlen (nextchar);
- X return '?';
- X }
- X }
- X else if (pfound->has_arg == 1)
- X {
- X if (optind < argc)
- X optarg = argv[optind++];
- X else
- X {
- X fprintf (stderr, "%s: option `%s' requires an argument\n",
- X argv[0], argv[optind - 1]);
- X nextchar += strlen (nextchar);
- X return '?';
- X }
- X }
- X nextchar += strlen (nextchar);
- X if (pfound->flag)
- X {
- X *(pfound->flag) = pfound->val;
- X return 0;
- X }
- X return pfound->val;
- X }
- X /* Can't find it as a long option. If this is getopt_long_only,
- X and the option starts with '-' and is a valid short
- X option, then interpret it as a short option. Otherwise it's
- X an error. */
- X if (_getopt_long_only == 0 || argv[optind][0] == '+' ||
- X index (optstring, *nextchar) == 0)
- X {
- X if (opterr != 0)
- X fprintf (stderr, "%s: unrecognized option `%c%s'\n",
- X argv[0], argv[optind][0], nextchar);
- X nextchar += strlen (nextchar);
- X optind++;
- X return '?';
- X }
- X }
- X
- X /* Look at and handle the next option-character. */
- X
- X {
- X char c = *nextchar++;
- X char *temp = index (optstring, c);
- X
- X /* Increment `optind' when we start to process its last character. */
- X if (*nextchar == 0)
- X optind++;
- X
- X if (temp == 0 || c == ':')
- X {
- X if (opterr != 0)
- X {
- X if (c < 040 || c >= 0177)
- X fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
- X argv[0], c);
- X else
- X fprintf (stderr, "%s: unrecognized option `-%c'\n",
- X argv[0], c);
- X }
- X return '?';
- X }
- X if (temp[1] == ':')
- X {
- X if (temp[2] == ':')
- X {
- X /* This is an option that accepts an argument optionally. */
- X if (*nextchar != 0)
- X {
- X optarg = nextchar;
- X optind++;
- X }
- X else
- X optarg = 0;
- X nextchar = 0;
- X }
- X else
- X {
- X /* This is an option that requires an argument. */
- X if (*nextchar != 0)
- X {
- X optarg = nextchar;
- X /* If we end this ARGV-element by taking the rest as an arg,
- X we must advance to the next element now. */
- X optind++;
- X }
- X else if (optind == argc)
- X {
- X if (opterr != 0)
- X fprintf (stderr, "%s: option `-%c' requires an argument\n",
- X argv[0], c);
- X c = '?';
- X }
- X else
- X /* We already incremented `optind' once;
- X increment it again when taking next ARGV-elt as argument. */
- X optarg = argv[optind++];
- X nextchar = 0;
- X }
- X }
- X return c;
- X }
- X}
- X
- X#ifdef TEST
- X
- X/* Compile with -DTEST to make an executable for use in testing
- X the above definition of `getopt'. */
- X
- Xint
- Xmain (argc, argv)
- X int argc;
- X char **argv;
- X{
- X int c;
- X int digit_optind = 0;
- X
- X while (1)
- X {
- X int this_option_optind = optind ? optind : 1;
- X
- X c = getopt (argc, argv, "abc:d:0123456789");
- X if (c == EOF)
- X break;
- X
- X switch (c)
- X {
- X case '0':
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X if (digit_optind != 0 && digit_optind != this_option_optind)
- X printf ("digits occur in two different argv-elements.\n");
- X digit_optind = this_option_optind;
- X printf ("option %c\n", c);
- X break;
- X
- X case 'a':
- X printf ("option a\n");
- X break;
- X
- X case 'b':
- X printf ("option b\n");
- X break;
- X
- X case 'c':
- X printf ("option c with value `%s'\n", optarg);
- X break;
- X
- X case '?':
- X break;
- X
- X default:
- X printf ("?? getopt returned character code 0%o ??\n", c);
- X }
- X }
- X
- X if (optind < argc)
- X {
- X printf ("non-option ARGV-elements: ");
- X while (optind < argc)
- X printf ("%s ", argv[optind++]);
- X printf ("\n");
- X }
- X
- X exit (0);
- X}
- X
- X#endif /* TEST */
- END_OF_FILE
- if test 16740 -ne `wc -c <'getopt.c'`; then
- echo shar: \"'getopt.c'\" unpacked with wrong size!
- fi
- # end of 'getopt.c'
- fi
- if test -f 'util.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'util.c'\"
- else
- echo shar: Extracting \"'util.c'\" \(14888 characters\)
- sed "s/^X//" >'util.c' <<'END_OF_FILE'
- X/* Support routines for GNU DIFF.
- X Copyright (C) 1988, 1989 Free Software Foundation, Inc.
- X
- XThis file is part of GNU DIFF.
- X
- XGNU DIFF is free software; you can redistribute it and/or modify
- Xit under the terms of the GNU General Public License as published by
- Xthe Free Software Foundation; either version 1, or (at your option)
- Xany later version.
- X
- XGNU DIFF is distributed in the hope that it will be useful,
- Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
- XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- XGNU General Public License for more details.
- X
- XYou should have received a copy of the GNU General Public License
- Xalong with GNU DIFF; see the file COPYING. If not, write to
- Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- X
- X#include "diff.h"
- X
- X/* Use when a system call returns non-zero status.
- X TEXT should normally be the file name. */
- X
- Xvoid
- Xperror_with_name (text)
- X char *text;
- X{
- X fprintf (stderr, "%s: ", program);
- X perror (text);
- X}
- X
- X/* Use when a system call returns non-zero status and that is fatal. */
- X
- Xvoid
- Xpfatal_with_name (text)
- X char *text;
- X{
- X print_message_queue ();
- X fprintf (stderr, "%s: ", program);
- X perror (text);
- X exit (2);
- X}
- X
- X/* Print an error message from the format-string FORMAT
- X with args ARG1 and ARG2. */
- X
- Xvoid
- Xerror (format, arg, arg1)
- X char *format;
- X char *arg;
- X char *arg1;
- X{
- X fprintf (stderr, "%s: ", program);
- X fprintf (stderr, format, arg, arg1);
- X fprintf (stderr, "\n");
- X}
- X
- X/* Print an error message containing the string TEXT, then exit. */
- X
- Xvoid
- Xfatal (message)
- X char *message;
- X{
- X print_message_queue ();
- X error (message, "");
- X exit (2);
- X}
- X
- X/* Like printf, except if -l in effect then save the message and print later.
- X This is used for things like "binary files differ" and "Only in ...". */
- X
- Xvoid
- Xmessage (format, arg1, arg2)
- X char *format, *arg1, *arg2;
- X{
- X if (paginate_flag)
- X {
- X struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
- X if (msg_chain_end == 0)
- X msg_chain = msg_chain_end = new;
- X else
- X {
- X msg_chain_end->next = new;
- X msg_chain_end = new;
- X }
- X new->format = format;
- X new->arg1 = concat (arg1, "", "");
- X new->arg2 = concat (arg2, "", "");
- X new->next = 0;
- X }
- X else
- X printf (format, arg1, arg2);
- X}
- X
- X/* Output all the messages that were saved up by calls to `message'. */
- X
- Xvoid
- Xprint_message_queue ()
- X{
- X struct msg *m;
- X
- X for (m = msg_chain; m; m = m->next)
- X printf (m->format, m->arg1, m->arg2);
- X}
- X
- X/* Call before outputting the results of comparing files NAME0 and NAME1
- X to set up OUTFILE, the stdio stream for the output to go to.
- X
- X Usually, OUTFILE is just stdout. But when -l was specified
- X we fork off a `pr' and make OUTFILE a pipe to it.
- X `pr' then outputs to our stdout. */
- X
- Xvoid
- Xsetup_output (name0, name1, depth)
- X char *name0, *name1;
- X int depth;
- X{
- X char *name;
- X
- X /* Construct the header of this piece of diff. */
- X name = (char *) xmalloc (strlen (name0) + strlen (name1)
- X + strlen (switch_string) + 15);
- X
- X strcpy (name, "diff");
- X strcat (name, switch_string);
- X strcat (name, " ");
- X strcat (name, name0);
- X strcat (name, " ");
- X strcat (name, name1);
- X
- X if (paginate_flag)
- X {
- X int pipes[2];
- X int desc;
- X
- X /* For a `pr' and make OUTFILE a pipe to it. */
- X if (pipe (pipes) < 0)
- X pfatal_with_name ("pipe");
- X
- X fflush (stdout);
- X
- X desc = vfork ();
- X if (desc < 0)
- X pfatal_with_name ("vfork");
- X
- X if (desc == 0)
- X {
- X close (pipes[1]);
- X if (pipes[0] != fileno (stdin))
- X {
- X if (dup2 (pipes[0], fileno (stdin)) < 0)
- X pfatal_with_name ("dup2");
- X close (pipes[0]);
- X }
- X
- X if (execl (PR_FILE_NAME, PR_FILE_NAME, "-f", "-h", name, 0) < 0)
- X pfatal_with_name (PR_FILE_NAME);
- X }
- X else
- X {
- X close (pipes[0]);
- X outfile = fdopen (pipes[1], "w");
- X }
- X }
- X else
- X {
- X
- X /* If -l was not specified, output the diff straight to `stdout'. */
- X
- X outfile = stdout;
- X
- X /* If handling multiple files (because scanning a directory),
- X print which files the following output is about. */
- X if (depth > 0)
- X printf ("%s\n", name);
- X }
- X
- X free (name);
- X}
- X
- X/* Call after the end of output of diffs for one file.
- X Close OUTFILE and get rid of the `pr' subfork. */
- X
- Xvoid
- Xfinish_output ()
- X{
- X if (outfile != stdout)
- X {
- X fclose (outfile);
- X wait (0);
- X }
- X}
- X
- X/* Compare two lines (typically one from each input file)
- X according to the command line options.
- X Each line is described by a `struct line_def'.
- X Return 1 if the lines differ, like `bcmp'. */
- X
- Xint
- Xline_cmp (s1, s2)
- X struct line_def *s1, *s2;
- X{
- X register char *t1, *t2;
- X register char end_char = line_end_char;
- X int savechar;
- X
- X /* Check first for exact identity.
- X If that is true, return 0 immediately.
- X This detects the common case of exact identity
- X faster than complete comparison would. */
- X
- X t1 = s1->text;
- X t2 = s2->text;
- X
- X /* Alter the character following line 2 so it doesn't
- X match that following line 1.
- X (We used to alter the character after line 1,
- X but that caused trouble if line 2 directly follows line 1.) */
- X savechar = s2->text[s2->length];
- X s2->text[s2->length] = s1->text[s1->length] + 1;
- X
- X /* Now find the first mismatch; this won't go past the
- X character we just changed. */
- X while (*t1++ == *t2++);
- X
- X /* Undo the alteration. */
- X s2->text[s2->length] = savechar;
- X
- X /* If the comparison stopped at the alteration,
- X the two lines are identical. */
- X if (t2 == s2->text + s2->length + 1)
- X return 0;
- X
- X /* Not exactly identical, but perhaps they match anyway
- X when case or whitespace is ignored. */
- X
- X if (ignore_case_flag || ignore_space_change_flag || ignore_all_space_flag)
- X {
- X t1 = s1->text;
- X t2 = s2->text;
- X
- X while (1)
- X {
- X register char c1 = *t1++;
- X register char c2 = *t2++;
- X
- X /* Ignore horizontal whitespace if -b or -w is specified. */
- X
- X if (ignore_all_space_flag)
- X {
- X /* For -w, just skip past any spaces or tabs. */
- X while (c1 == ' ' || c1 == '\t') c1 = *t1++;
- X while (c2 == ' ' || c2 == '\t') c2 = *t2++;
- X }
- X else if (ignore_space_change_flag)
- X {
- X /* For -b, advance past any sequence of whitespace in line 1
- X and consider it just one Space, or nothing at all
- X if it is at the end of the line. */
- X if (c1 == ' ' || c1 == '\t')
- X {
- X while (1)
- X {
- X c1 = *t1++;
- X if (c1 == end_char)
- X break;
- X if (c1 != ' ' && c1 != '\t')
- X {
- X --t1;
- X c1 = ' ';
- X break;
- X }
- X }
- X }
- X
- X /* Likewise for line 2. */
- X if (c2 == ' ' || c2 == '\t')
- X {
- X while (1)
- X {
- X c2 = *t2++;
- X if (c2 == end_char)
- X break;
- X if (c2 != ' ' && c2 != '\t')
- X {
- X --t2;
- X c2 = ' ';
- X break;
- X }
- X }
- X }
- X }
- X
- X /* Upcase all letters if -i is specified. */
- X
- X if (ignore_case_flag)
- X {
- X if (islower (c1))
- X c1 = toupper (c1);
- X if (islower (c2))
- X c2 = toupper (c2);
- X }
- X
- X if (c1 != c2)
- X break;
- X if (c1 == end_char)
- X return 0;
- X }
- X }
- X
- X return (1);
- X}
- X
- X/* Find the consecutive changes at the start of the script START.
- X Return the last link before the first gap. */
- X
- Xstruct change *
- Xfind_change (start)
- X struct change *start;
- X{
- X return start;
- X}
- X
- Xstruct change *
- Xfind_reverse_change (start)
- X struct change *start;
- X{
- X return start;
- X}
- X
- X/* Divide SCRIPT into pieces by calling HUNKFUN and
- X print each piece with PRINTFUN.
- X Both functions take one arg, an edit script.
- X
- X HUNKFUN is called with the tail of the script
- X and returns the last link that belongs together with the start
- X of the tail.
- X
- X PRINTFUN takes a subscript which belongs together (with a null
- X link at the end) and prints it. */
- X
- Xvoid
- Xprint_script (script, hunkfun, printfun)
- X struct change *script;
- X struct change * (*hunkfun) ();
- X void (*printfun) ();
- X{
- X struct change *next = script;
- X
- X while (next)
- X {
- X struct change *this, *end;
- X
- X /* Find a set of changes that belong together. */
- X this = next;
- X end = (*hunkfun) (next);
- X
- X /* Disconnect them from the rest of the changes,
- X making them a hunk, and remember the rest for next iteration. */
- X next = end->link;
- X end->link = NULL;
- X#ifdef DEBUG
- X debug_script (this);
- X#endif
- X
- X /* Print this hunk. */
- X (*printfun) (this);
- X
- X /* Reconnect the script so it will all be freed properly. */
- X end->link = next;
- X }
- X}
- X
- X/* Print the text of a single line LINE,
- X flagging it with the characters in LINE_FLAG (which say whether
- X the line is inserted, deleted, changed, etc.). */
- X
- Xvoid
- Xprint_1_line (line_flag, line)
- X char *line_flag;
- X struct line_def *line;
- X{
- X int length = line->length; /* must be nonzero */
- X const char *text = line->text; /* Help the compiler. */
- X FILE *out = outfile; /* Help the compiler some more. */
- X
- X /* If -T was specified, use a Tab between the line-flag and the text.
- X Otherwise use a Space (as Unix diff does).
- X Print neither space nor tab if line-flags are empty. */
- X
- X if (line_flag != NULL && line_flag[0] != 0)
- X fprintf (out, tab_align_flag ? "%s\t" : "%s ", line_flag);
- X
- X /* Now output the contents of the line.
- X If -t was specified, expand tabs to spaces.
- X Otherwise output verbatim. */
- X
- X if (tab_expand_flag)
- X {
- X register int column = 0;
- X register int i;
- X for (i = 0; i < line->length; i++)
- X {
- X register char c = line->text[i];
- X switch (c)
- X {
- X case '\t':
- X column++;
- X while (column & 7)
- X {
- X putc (' ', out);
- X column++;
- X }
- X c = ' ';
- X break;
- X case '\b':
- X column--;
- X break;
- X default:
- X column++;
- X break;
- X }
- X putc (c, out);
- X }
- X }
- X else
- X fwrite (text, sizeof (char), length, out);
- X if ((line_flag == NULL || line_flag[0] != 0) && text[length - 1] != '\n'
- X && line_end_char == '\n')
- X fprintf (out, "\n\\ No newline at end of file\n");
- X}
- X
- Xchange_letter (inserts, deletes)
- X int inserts, deletes;
- X{
- X if (!inserts)
- X return 'd';
- X else if (!deletes)
- X return 'a';
- X else
- X return 'c';
- X}
- X
- X/* Translate an internal line number (an index into diff's table of lines)
- X into an actual line number in the input file.
- X The internal line number is LNUM. FILE points to the data on the file.
- X
- X Internal line numbers count from 0 within the current chunk.
- X Actual line numbers count from 1 within the entire file;
- X in addition, they include lines ignored for comparison purposes.
- X
- X The `ltran' feature is no longer in use. */
- X
- Xint
- Xtranslate_line_number (file, lnum)
- X struct file_data *file;
- X int lnum;
- X{
- X return lnum + 1;
- X}
- X
- Xvoid
- Xtranslate_range (file, a, b, aptr, bptr)
- X struct file_data *file;
- X int a, b;
- X int *aptr, *bptr;
- X{
- X *aptr = translate_line_number (file, a - 1) + 1;
- X *bptr = translate_line_number (file, b + 1) - 1;
- X}
- X
- X/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
- X If the two numbers are identical, print just one number.
- X
- X Args A and B are internal line numbers.
- X We print the translated (real) line numbers. */
- X
- Xvoid
- Xprint_number_range (sepchar, file, a, b)
- X char sepchar;
- X struct file_data *file;
- X int a, b;
- X{
- X int trans_a, trans_b;
- X translate_range (file, a, b, &trans_a, &trans_b);
- X
- X /* Note: we can have B < A in the case of a range of no lines.
- X In this case, we should print the line number before the range,
- X which is B. */
- X if (trans_b > trans_a)
- X fprintf (outfile, "%d%c%d", trans_a, sepchar, trans_b);
- X else
- X fprintf (outfile, "%d", trans_b);
- X}
- X
- X/* Look at a hunk of edit script and report the range of lines in each file
- X that it applies to. HUNK is the start of the hunk, which is a chain
- X of `struct change'. The first and last line numbers of file 0 are stored in
- X *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
- X Note that these are internal line numbers that count from 0.
- X
- X If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
- X
- X Also set *DELETES nonzero if any lines of file 0 are deleted
- X and set *INSERTS nonzero if any lines of file 1 are inserted.
- X If only ignorable lines are inserted or deleted, both are
- X set to 0. */
- X
- Xvoid
- Xanalyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
- X struct change *hunk;
- X int *first0, *last0, *first1, *last1;
- X int *deletes, *inserts;
- X{
- X int f0, l0, f1, l1, show_from, show_to;
- X int i;
- X int nontrivial = !(ignore_blank_lines_flag || ignore_regexp);
- X struct change *next;
- X
- X show_from = show_to = 0;
- X
- X f0 = hunk->line0;
- X f1 = hunk->line1;
- X
- X for (next = hunk; next; next = next->link)
- X {
- X l0 = next->line0 + next->deleted - 1;
- X l1 = next->line1 + next->inserted - 1;
- X show_from += next->deleted;
- X show_to += next->inserted;
- X
- X for (i = next->line0; i <= l0 && ! nontrivial; i++)
- X if ((!ignore_blank_lines_flag || files[0].linbuf[i].length > 1)
- X && (!ignore_regexp
- X || 0 > re_search (&ignore_regexp_compiled,
- X files[0].linbuf[i].text,
- X files[0].linbuf[i].length, 0,
- X files[0].linbuf[i].length, 0)))
- X nontrivial = 1;
- X
- X for (i = next->line1; i <= l1 && ! nontrivial; i++)
- X if ((!ignore_blank_lines_flag || files[1].linbuf[i].length > 1)
- X && (!ignore_regexp
- X || 0 > re_search (&ignore_regexp_compiled,
- X files[1].linbuf[i].text,
- X files[1].linbuf[i].length, 0,
- X files[1].linbuf[i].length, 0)))
- X nontrivial = 1;
- X }
- X
- X *first0 = f0;
- X *last0 = l0;
- X *first1 = f1;
- X *last1 = l1;
- X
- X /* If all inserted or deleted lines are ignorable,
- X tell the caller to ignore this hunk. */
- X
- X if (!nontrivial)
- X show_from = show_to = 0;
- X
- X *deletes = show_from;
- X *inserts = show_to;
- X}
- X
- X/* malloc a block of memory, with fatal error message if we can't do it. */
- X
- XVOID *
- Xxmalloc (size)
- X unsigned size;
- X{
- X register VOID *value;
- X
- X if (size == 0)
- X size = 1;
- X
- X value = (VOID *) malloc (size);
- X
- X if (!value)
- X fatal ("virtual memory exhausted");
- X return value;
- X}
- X
- X/* realloc a block of memory, with fatal error message if we can't do it. */
- X
- XVOID *
- Xxrealloc (old, size)
- X VOID *old;
- X unsigned int size;
- X{
- X register VOID *value;
- X
- X if (size == 0)
- X size = 1;
- X
- X value = (VOID *) realloc (old, size);
- X
- X if (!value)
- X fatal ("virtual memory exhausted");
- X return value;
- X}
- X
- X/* Concatenate three strings, returning a newly malloc'd string. */
- X
- Xchar *
- Xconcat (s1, s2, s3)
- X char *s1, *s2, *s3;
- X{
- X int len = strlen (s1) + strlen (s2) + strlen (s3);
- X char *new = (char *) xmalloc (len + 1);
- X strcpy (new, s1);
- X strcat (new, s2);
- X strcat (new, s3);
- X return new;
- X}
- X
- Xdebug_script (sp)
- X struct change *sp;
- X{
- X fflush (stdout);
- X for (; sp; sp = sp->link)
- X fprintf (stderr, "%3d %3d delete %d insert %d\n",
- X sp->line0, sp->line1, sp->deleted, sp->inserted);
- X fflush (stderr);
- X}
- END_OF_FILE
- if test 14888 -ne `wc -c <'util.c'`; then
- echo shar: \"'util.c'\" unpacked with wrong size!
- fi
- # end of 'util.c'
- fi
- echo shar: End of archive 3 \(of 8\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 8 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
- exit 0 # Just in case...
-